#include <stdint.h>

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;

typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;

#define DEBUG 2

typedef struct {
    u16 type;   //Type,  开始的3个字节不使用
    u16 stat;   //Status //
    u32 freq;   //Frequency Calculation Value
    u32 loop;   //Loop Start Point
    u32 size;   //Sampling Number
    s8 data[1]; //Sampling Data Order
} WaveData;

enum{
    WaveData_sample_ext = 1<<4, //
};

typedef struct {
    u8 typ;         //Type
    u8 key;         //Original Key
    u8 len;         //Sound Length (Compatible Sound)
    u8 p_s;         //Pan or Sweep (Compatible Sound 1)
    WaveData *wav;  //Wave Data Address
    u8 att;         //Attack
    u8 dec;         //Decay
    u8 sus;         //Sustain
    u8 rel;         //Release
} ToneData;

typedef struct {
    u8 sf;          //Status
    u8 ty;          //Type
    u8 rv;          //Right Volume
    u8 lv;          //Left Volume
    u8 at;          //Attack
    u8 de;          //Decay
    u8 su;          //Sustain
    u8 re;          //Release
    u8 r1[24];      // (reserved)
    u32 fr;         //Frequency Calculation Value
    WaveData *wp;   //Wave Pointer
    u32 r3[6];      // (reserved)
} SoundChannel;


//先实现禁音
//hack MPlayMain函数
int _0x80D4860(){
        asm("WAVE_DATA:\n");
    //asm(".incbin \"d:/Encounter2.bin\"\n");

    asm("W1_DATA: .incbin \"d:/gbainsn/square12.bin\"\n");
    asm("W2_DATA: .incbin \"d:/gbainsn/square25.bin\"\n");
    asm("W3_DATA: .incbin \"d:/gbainsn/square50.bin\"\n");
    asm("W4_DATA: .incbin \"d:/gbainsn/square75.bin\"\n");
    asm("W5_DATA: .incbin \"d:/gbainsn/t2.bin\"\n");
    asm("W6_DATA: .incbin \"d:/gbainsn/noise.bin\"\n");

    #if DEBUG==2
    #define DEF_WDATA(n) asm("XW"#n"_DATA: .incbin \"d:/gbainsn/flatOutLies/"#n".bin\"");
    //asm("XW1_DATA: .incbin \"d:/gbainsn/flatOutLies/01.bin\"\n");
    DEF_WDATA(01);
    DEF_WDATA(02);
    DEF_WDATA(03);
    DEF_WDATA(04);
    DEF_WDATA(05);
    DEF_WDATA(06);
    DEF_WDATA(07);
    DEF_WDATA(08);
    DEF_WDATA(09);
    DEF_WDATA(10);
    DEF_WDATA(11);
    DEF_WDATA(12);
    //DEF_WDATA(13);
    //DEF_WDATA(14);
    DEF_WDATA(15);
    DEF_WDATA(16);
    DEF_WDATA(17);
    DEF_WDATA(18);
    DEF_WDATA(19);
    DEF_WDATA(20);
    DEF_WDATA(21);
    DEF_WDATA(22);
    DEF_WDATA(23);
    DEF_WDATA(24);
    DEF_WDATA(25);
    DEF_WDATA(26);
    DEF_WDATA(27);
    DEF_WDATA(28);
    DEF_WDATA(29);
    DEF_WDATA(30);
    DEF_WDATA(31);
    #undef DEF_WDATA
    #endif


    asm("mov r0,r0\n");
    asm("JMP80D4860_r2:\n");
    asm("ldr r2,=0x68736D53\n");
    asm("ldr r3,[r0,#0x34]\n");
    asm("cmp r2,r3\n");
    asm("beq CALL\n");
    asm("bx  lr\n");
    asm("CALL:\n");
    asm("push {r0,r1,r2,r3,lr}\n");
    asm("bl sound_hack\n");
    asm("cmp r0,#0");
    asm("beq CONTINUE\n");
    asm("pop {r0,r1,r2,r3}\n");
    asm("pop {r0}\n");
    asm("bx r0\n");
    asm("CONTINUE:\n");
    asm("pop {r0,r1,r2,r3}\n");
    asm("add r3,#1\n");
    asm("str r3,[r0,#0x34]\n");
    asm("pop {r3}\n");
    asm("mov lr,r3\n");
    asm("ldr r3,=0x80D486E+1\n");
    asm("bx  r3\n");
}



extern WaveData WAVE_DATA;
extern WaveData W1_DATA;
extern WaveData W2_DATA;
extern WaveData W3_DATA;
extern WaveData W4_DATA;
extern WaveData W5_DATA;
extern WaveData W6_DATA;
enum{
m_C_1,
m_Cs1,
m_D_1,
m_Ds1,
m_E_1,
m_F_1,
m_Fs1,
m_G_1,
m_Gs1,
m_A_1,
m_As1,
m_B_1,

m_C_2,
m_Cs2,
m_D_2,
m_Ds2,
m_E_2,
m_F_2,
m_Fs2,
m_G_2,
m_Gs2,
m_A_2,
m_As2,
m_B_2,

m_C_3,
m_Cs3,
m_D_3,
m_Ds3,
m_E_3,
m_F_3,
m_Fs3,
m_G_3,
m_Gs3,
m_A_3,
m_As3,
m_B_3,

m_C_4,
m_Cs4,
m_D_4,
m_Ds4,
m_E_4,
m_F_4,
m_Fs4,
m_G_4,
m_Gs4,
m_A_4,
m_As4,
m_B_4,

m_C_5,
m_Cs5,
m_D_5,
m_Ds5,
m_E_5,
m_F_5,
m_Fs5,
m_G_5,
m_Gs5,
m_A_5,
m_As5,
m_B_5,

m_C_6,
m_Cs6,
m_D_6,
m_Ds6,
m_E_6,
m_F_6,
m_Fs6,
m_G_6,
m_Gs6,
m_A_6,
m_As6,
m_B_6,

m_C_7,
m_Cs7,
m_D_7,
m_Ds7,
m_E_7,
m_F_7,
m_Fs7,
m_G_7,
m_Gs7,
m_A_7,
m_As7,
m_B_7,

m_C_8,
m_Cs8,
m_D_8,
m_Ds8,
m_E_8,
m_F_8,
m_Fs8,
m_G_8,
m_Gs8,
m_A_8,
m_As8,
m_B_8,

m_C_9,
m_Cs9,
m_D_9,
m_Ds9,
m_E_9,
m_F_9,
m_Fs9,
m_G_9,
m_Gs9,
m_A_9,
m_As9,
m_B_9,

m_Node_off = 0x80,
m_Node_on,
m_wait,
m_insn,
m_vol,
m_setc,
m_loop,
};

typedef struct{
    uint8_t  *mod_data;
    uint8_t  *mod_base;
    int16_t  wait;
    int8_t   key;
}HackChannel;

typedef struct{
    HackChannel channel[2];
}HackSound;

typedef struct{
    int32_t wait;
    uint8_t *mod_data;
    uint8_t *mod_base;
}HackSoundA;

const WaveData * const insn[] = {
    &W1_DATA,
    &W2_DATA,
    &W3_DATA,
    &W4_DATA,
    &W5_DATA,
    &W6_DATA,
};

#if DEBUG==2

#define DEF_WDATA(n) extern WaveData  XW##n##_DATA;;
    DEF_WDATA(01)
    DEF_WDATA(02)
    DEF_WDATA(03)
    DEF_WDATA(04)
    DEF_WDATA(05)
    DEF_WDATA(06)
    DEF_WDATA(07)
    DEF_WDATA(08)
    DEF_WDATA(09)
    DEF_WDATA(10)
    DEF_WDATA(11)
    DEF_WDATA(12)
    //DEF_WDATA(13);
    //DEF_WDATA(14);
    DEF_WDATA(15)
    DEF_WDATA(16)
    DEF_WDATA(17)
    DEF_WDATA(18)
    DEF_WDATA(19)
    DEF_WDATA(20)
    DEF_WDATA(21)
    DEF_WDATA(22)
    DEF_WDATA(23)
    DEF_WDATA(24)
    DEF_WDATA(25)
    DEF_WDATA(26)
    DEF_WDATA(27)
    DEF_WDATA(28)
    DEF_WDATA(29)
    DEF_WDATA(30)
    DEF_WDATA(31)

const WaveData *const insn2[] = {
#define DEF_WDATA(n)  &XW##n##_DATA,
    DEF_WDATA(01)
    DEF_WDATA(02)
    DEF_WDATA(03)
    DEF_WDATA(04)
    DEF_WDATA(05)
    DEF_WDATA(06)
    DEF_WDATA(07)
    DEF_WDATA(08)
    DEF_WDATA(09)
    DEF_WDATA(10)
    DEF_WDATA(11)
    DEF_WDATA(12)
    DEF_WDATA(12)
    DEF_WDATA(12)
    DEF_WDATA(15)
    DEF_WDATA(16)
    DEF_WDATA(17)
    DEF_WDATA(18)
    DEF_WDATA(19)
    DEF_WDATA(20)
    DEF_WDATA(21)
    DEF_WDATA(22)
    DEF_WDATA(23)
    DEF_WDATA(24)
    DEF_WDATA(25)
    DEF_WDATA(26)
    DEF_WDATA(27)
    DEF_WDATA(28)
    DEF_WDATA(29)
    DEF_WDATA(30)
    DEF_WDATA(31)
};
#endif

const uint8_t channel_data[] = {
#include "sound_data.c"
m_loop,
};


const uint8_t channel3_data[] = {
#include "sound_data3.c"
m_loop,
};

const uint8_t channel1_data[] = {
#include "sound_data1.c"
m_loop,
};

const uint8_t sound_data1[] = {
#include "sound2_data1.h"
    // m_insn,2,
    // m_C_6,
    // m_wait,0x20,
    m_loop,
};

const uint8_t sound_data2[] = {
#include "sound2_data2.h"
    m_loop,
};

const uint8_t sound_data3[] = {
#include "sound2_data3.h"
    m_loop,
};

const uint8_t sound_data4[] = {
#include "sound2_data4.h"
    m_loop,
};

const uint8_t sounda_data[] = {
    #include "sound_a.h"
    m_loop,
};

typedef int (*callT)();
#define CALLT(addr,...) ((callT)(addr+1))(__VA_ARGS__)

int sound_hack(uint32_t r0){
    uint32_t *p = (uint32_t*)0x030053f0;
    if(!*p){
        return 0;
    }
    SoundChannel *c = (void*)(0x3005400 + 0x50);
    #if 0
    c->wp = &WAVE_DATA;
    if(*p==1){
        c->r3[0] = 0;
        c->fr = //WAVE_DATA.freq;
            CALLT(0x80D4DCC,&WAVE_DATA,0x3c,0);
        *p = 2;
    }
    #elif 0
    HackSound *hs = (void*)0x030053c0;;
    int i;
    for(i=0;i<3;i++){
        HackChannel *hc =hs->channel+i;

        if(*p==1){
            if(!hc->mod_base){
                if(i==0){
                    hc->mod_base = //channel3_data;
                        sound_data1;
                    //一般三角波需要 key + 24
                }
                else if(i==1){
                    hc->mod_base = //channel_data;
                        sound_data2;
                    //key + 12
                }
                else if(i==2){
                    hc->mod_base = //channel1_data;
                        sound_data3;
                    //key + 12
                }
                c->lv = 0x80;
                c->rv = 0x80;
            }
            if(!hc->mod_data){
                hc->mod_data = hc->mod_base;
            }
            if(hc->wait--<=0){
                int quit = 0;
                while(!quit){
                    int v = *hc->mod_data++;
                    if(v<0x80){
                        if(c->wp){
                            // c->sf = *(uint8_t*)0x03005300;
                            // if(c->sf==0){
                            //     c->sf = 0x11;
                            // }
                            //c->sf = 0x01;
                            c->sf = 0x81;  //0x11 表示循环，0x81表示一次
                            //c->sf = 0x11;
                            c->fr = CALLT(0x80D4DCC,
                                //&WAVE_DATA,
                                c->wp,
                                v+12*1,0); //数值越大，则越快
                        }
                    }
                    else{
                        switch (v)
                        {
                        case m_wait:
                            hc->wait = *hc->mod_data++;
                            hc->wait *= 0x5;
                            if(hc->wait>0){
                                quit = 1;
                            }
                            break;
                        case m_vol: //设置音量
                            c->rv = 4*(*hc->mod_data++);
                            c->lv = c->lv;
                            break;
                        case m_insn://切换乐器
                            c->wp = insn2[(*hc->mod_data++)-1];
                            c->r3[0] = (uint32_t)c->wp->data;
                            break;
                        case m_loop:
                            hc->mod_data = 0;
                            quit = 1;
                            break;
                        case m_Node_off:
                            c->lv = 0;
                            c->rv = 0;
                            //c->sf = 0;
                            break;
                        default:
                            break;
                        }
                    }
                }
            }
        }
        c = (void*)((uint32_t)c+0x40);
    }
    #else
    HackSoundA *hs = (void*)0x030053c0;;
    if(!hs->mod_base){
        hs->mod_base = sounda_data;
    }
    if(!hs->mod_data){
        hs->mod_data = hs->mod_base;
    }
    SoundChannel *cc = c;
    if(hs->wait--<0){
        int quit = 0;
        while(!quit){
            int v = *hs->mod_data++;
            if(v==m_loop){
                //初始化
                hs->mod_data = hs->mod_base;
            }
            else if(v<0x80){
                cc->sf = 0x81; //不循环的声音
                if(cc->wp){
                    // c->sf = *(uint8_t*)0x03005300;
                    // if(c->sf==0){
                    //     c->sf = 0x11;
                    // }
                    //c->sf = 0x01;
                    cc->sf = 0x81;  //0x11 表示循环，0x81表示一次
                    //c->sf = 0x11;
                    cc->lv = 0x80;
                    cc->rv = 0x80;
                    cc->fr = CALLT(0x80D4DCC,
                        //&WAVE_DATA,
                        cc->wp,
                        v+12*1,0); //数值越大，则越快
                }
            }
            else{
                switch (v)
                {
                case m_wait:
                    hs->wait = *hs->mod_data++;
                    hs->wait *= 0x5;
                    if(hs->wait>0){
                        quit = 1;
                    }
                    break;
                case m_setc:
                    cc = c + (*hs->mod_data++)-1;
                    break;
                case m_vol: //设置音量
                    cc->rv = 4*(*hs->mod_data++);
                    cc->lv = c->lv;
                    break;
                case m_insn://切换乐器
                    cc->wp = insn2[(*hs->mod_data++)-1];
                    cc->r3[0] = (uint32_t)c->wp->data;
                    break;
                case m_Node_off:
                    cc->lv = 0;
                    cc->rv = 0;
                    //c->sf = 0;
                    break;
                default:
                    break;
                }
            }
        }
    }
    #endif
    return 1;
}


/*
对于mod音乐，声音样本会有个循环开始和循环结束
*/

/*
void _80D42DC(){
    asm("mov r0,r0\n");
    //asm("JMP80D42DC_r3:\n");
    asm("JMP3002ca0_r3:\n");
    asm("str r0,[sp,#4]\n");
    asm("ldr r3,[r4,#0x24]\n");

    //修改
    asm("push {r1,r2,r3}\n");
    asm("mov r0,r3\n");
    asm("mov r1,r4\n");
    asm("bl hack_sound_set\n");
    asm("pop {r1,r2,r3}\n");
    asm("mov r3,r0\n");
    //结束

    asm("ldr r0,[sp,#20]\n");
    asm("cmp r0,#0\n");
    asm("beq JMP1\n");
    asm("ldr r1,=0x3002caa+1\n");
    asm("bx r1\n");
    asm("JMP1: \n");
    asm("ldr r6,=0x3002cc1\n");
    asm("bx  r6");
}

uint32_t hack_sound_set(uint32_t r0,uint32_t r1){
    *(int*)0x030053b0 = r0;
    *(int*)0x030053b4 = r1;
    r0 += 0x0;
    return r0;
}

*/

// int _080D43C0(){
//     asm("mov r0,r0\n");
//     #if 0
//     asm("JMP80D43C0_r0:\n");
//     #else
//     asm("JMP3002d84_r0:\n");
//     #endif
//     asm("mov r0,r3\n");
//     asm("mov r1,sp\n");
//     asm("push {r3}\n");
//     asm("bl hack_sound_loop\n");
//     asm("pop {r3}\n");
//     asm("ldr r5,=0x80D43D0+1\n");
//     asm("bx r5\n");
//     asm("\n");
// }

void hack_sound_loop(uint32_t r3,uint32_t sp){
    WaveData *w = (void*)r3;
    *(uint32_t*)(sp+0xc) = //*(uint32_t*)(r3+8) + r3 + 0x10;
        (uint32_t)(w->data+w->loop+0x10);
    *(uint32_t*)(sp+0x10) = w->size-w->loop;
    #if HACK
    uint32_t v = *(uint32_t*)r3;
    v &= 0xffffff;
    if(v&0x800000){
        v &= 0x7fffff;
        *(uint32_t*)(sp+0x10) = v - w->loop; //在指定范围内循环
    }
    #endif
}


